package org.vacoor.nothing.common.reflect;

import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import java.util.Arrays;
import java.util.Map;
import java.util.Set;

/**
 * Property
 */
public class Property<T> {
    private final String name = "unknown";
    // private readMethod, 严格模式必须同时拥有 getter/setter 不严格模式只要有 getter

    static <T> Property<T> lookup(Class<?> clazz, String name) {
        return null;
    }

    static <T> Property<T>[] lookup(Class<?> clazz) {
        return new Property[0];
    }

    T getValue() {
        return null;
    }

    // TODO 内部要不要维护实例
    void setValue(Object obj, T value) {

    }

    void setValue(T value) {
    }

    boolean canAcceptType(Class<?> valueType) {
        return getType().isAssignableFrom(valueType);
    }

    Class<T> getType() {
        return null;
    }

    void applyTo(Class<?> clazz) {
        apply(clazz, this);
    }

    static <T> void apply(Class<?> clazz, Property<T> property) {
        Property<T> ownedProp = lookup(clazz, property.name);
        if (null != ownedProp) {
            if (!ownedProp.canAcceptType(property.getType())) {
                throw new IllegalArgumentException("Not compatible 不兼容的类型");    // TODO 创建一个新异常
            }
            ownedProp.setValue(property.getValue());
        }
    }

    static <T> void apply(Class<?> clazz, Property<T>... properties) {
        if (1 > properties.length) {
            return;
        }

        Map<String, Property<T>> ownedProps = Maps.uniqueIndex(Arrays.asList(Property.<T>lookup(clazz)), new Function<Property<T>, String>() {
            @Override
            public String apply(Property<T> input) {
                return input.name;
            }
        });
        if (1 > ownedProps.size()) {
            return;
        }
        Set<Property<T>> props = Sets.newHashSet(properties);   // 去重
        for (Property<T> prop : props) {
            if (ownedProps.containsKey(prop.name)) {
                Property<T> ownedProp = ownedProps.get(prop.name);
                ownedProp.setValue(prop.getValue());
            }
        }
    }

    public static void main(String[] args) {
    }
}
